package com.love.utils.redis;

import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisHelper {
	private static final String SET_SUCCESS = "OK";
	private static JedisPool pool = null;
	
	private RedisHelper(){}

	/**
	 * 构建redis连接池
	 * @return JedisPool
	 */
	public synchronized static JedisPool getPool() {
		if (pool == null) {
			JedisPoolConfig config = new JedisPoolConfig();
			// 控制一个pool可分配多少个jedis实例，通过pool.getResource()来获取；
			// 如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
			config.setMaxTotal(RedisConfig.getMaxActive());
			// 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。
			config.setMaxIdle(RedisConfig.getMaxIdle());
			// 表示当borrow(引入)一个jedis实例时，最大的等待时间，如果超过等待时间，则直接抛出JedisConnectionException；
			config.setMaxWaitMillis(RedisConfig.getMaxWait());
			// 在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
			config.setTestOnBorrow(RedisConfig.getTestOnBorrow());
			// 在return给pool时，是否提前进行validate操作
			config.setTestOnReturn(RedisConfig.getTestOnReturn());
			pool = new JedisPool(config, RedisConfig.getHost(), RedisConfig.getPort(), RedisConfig.getTimeOut());
		}
		return pool;
	}

	/**
	 * 返还到连接池
	 */
	public static void returnResource(JedisPool pool, Jedis redis) {
		if (redis != null) {
			pool.returnResource(redis);
		}
	}

	/**
	 * 获取数据
	 * @param key
	 * @return 
	 * @throws Exception 
	 */
	public static String get(String key) throws Exception {
		JedisPool pool = null;
		Jedis jedis = null;
		String value = null;
		try {
			pool = getPool();
			jedis = pool.getResource();
			value = jedis.get(key);
		} catch (Exception e) {
			throw e;
		} finally {
			// 返还到连接池
			returnResource(pool, jedis);
		}
		return value;
	}

	/**
	 * 设置/更新数据
	 * @param key
	 * @return
	 * @throws Exception 
	 */
	public static boolean set(String key, String value) throws Exception {
		JedisPool pool = null;
		Jedis jedis = null;
		boolean result = false;
		try {
			pool = getPool();
			jedis = pool.getResource();
			if(StringUtils.equalsIgnoreCase(SET_SUCCESS, jedis.set(key, value))){
				result = true;
			}
		} catch (Exception e) {
			throw e;
		} finally {
			// 返还到连接池
			returnResource(pool, jedis);
		}
		return result;
	}
	
    /**
     * 描述:元素递增
     * @param key
     * @return 失败/异常时返回null
     * @throws Exception 
     */
    public static Long incr(String key) throws Exception{
    	JedisPool pool = null;
        Jedis jedis = null;
        Long result = null;
        try {
            pool = getPool();
            jedis = pool.getResource();
            result = jedis.incr(key);
        } catch (Exception e) {
            throw e;
        } finally {
            //返还到连接池
            returnResource(pool, jedis);
        }
        return result;
    }
    
	/**
	 * 设置/更新数据，并且设置过期时间
	 * @param key
	 * @param timeout 单位：秒
	 * @param value
	 * @throws Exception 
	 */
	public static boolean setex(String key, int timeout, String value) throws Exception {
		JedisPool pool = null;
		Jedis jedis = null;
		boolean result = false;
		try {
			pool = getPool();
			jedis = pool.getResource();
			if (StringUtils.equalsIgnoreCase(SET_SUCCESS, jedis.setex(key, timeout, value))) {
				result = true;
			}
		} catch (Exception e) {
			throw e;
		} finally {
			// 返还到连接池
			returnResource(pool, jedis);
		}
		return result;
	}

	/**
	 * 设置/更新数据Hash
	 * @param key
	 * @param field
	 * @param value
	 * @return If the field already exists, and the HSET just produced an update of the value, 0 is returned, 
	 * 		   otherwise if a new field is created 1 is returned.
	 * @throws Exception 
	 */
	public static Long hset(String key, String field, String value) throws Exception {
		JedisPool pool = null;
		Jedis jedis = null;
		Long result = null;
		try {
			pool = getPool();
			jedis = pool.getResource();
			result = jedis.hset(key, field, value);
		} catch (Exception e) {
			throw e;
		} finally {
			// 返还到连接池
			returnResource(pool, jedis);
		}
		return result;
	}

	/**
	 * 从Hash中获取value
	 * @param key
	 * @param field
	 * @return
	 * @throws Exception 
	 */
	public static String hget(String key, String field) throws Exception {
		JedisPool pool = null;
		Jedis jedis = null;
		String value = null;
		try {
			pool = getPool();
			jedis = pool.getResource();
			value = jedis.hget(key, field);
		} catch (Exception e) {
			throw e;
		} finally {
			// 返还到连接池
			returnResource(pool, jedis);
		}
		return value;
	}

	/**
	 * 删除key
	 * @param key
	 * @return 删除个数
	 * @throws Exception 
	 */
	public static Long del(String key) throws Exception {
		JedisPool pool = null;
		Jedis jedis = null;
		Long result = null;
		try {
			pool = getPool();
			jedis = pool.getResource();
			result = jedis.del(key);
		} catch (Exception e) {
			throw e;
		} finally {
			// 返还到连接池
			returnResource(pool, jedis);
		}
		return result;
	}

	/**
	 * 获取keys
	 * @param pattern
	 * @return
	 * @throws Exception 
	 */
	public static Set<String> getKeys(String pattern) throws Exception {
		JedisPool pool = null;
		Jedis jedis = null;
		Set<String> keys = new HashSet<String>();
		try {
			pool = getPool();
			jedis = pool.getResource();
			keys = jedis.keys(pattern);
		} catch (Exception e) {
			throw e;
		} finally {
			// 返还到连接池
			returnResource(pool, jedis);
		}
		return keys;
	}

	/**
	 * 删除keys
	 * @param keys
	 * @return 删除个数
	 * @throws Exception 
	 */
	public static Long delKeys(String... keys) throws Exception {
		JedisPool pool = null;
		Jedis jedis = null;
		Long result = null;
		try {
			pool = getPool();
			jedis = pool.getResource();
			result = jedis.del(keys);
		} catch (Exception e) {
			throw e;
		} finally {
			// 返还到连接池
			returnResource(pool, jedis);
		}
		return result;
	}
		
	/**
	 * 针对key增加指定value
	 * @param key
	 * @param value
	 * @return Integer reply, this commands will reply with the new value of key after the increment.
	 * @throws Exception 
	 */
	public static Long incrby(String key, long value) throws Exception{
		JedisPool pool = null;
		Jedis jedis = null;
		Long result = null;
		try {
			pool = getPool();
			jedis = pool.getResource();
			result = jedis.incrBy(key, value);
		} catch (Exception e) {
			throw e;
		} finally {
			// 返还到连接池
			returnResource(pool, jedis);
		}
		return result;
	
	}
	
	public static void main(String[] args) {
		try {
			System.out.println(get("test1") == null);
			System.out.println(set("test2", "test2"));
			System.out.println(incr("incr"));
			System.out.println(setex("setex", 100, "setex"));
			System.out.println(hget("hget", "a"));
			System.out.println(del("hget"));
			System.out.println(getKeys("*"));
			System.out.println(incrby("incrby", 100));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
